import { logger } from '../../../types/constants'

/**
 * 事件阻止策略类型：
 * 1、一般执行顺序为： preventDefault > stopPropagation > stopImmediatePropagation
 * 1）preventDefault()：阻止'浏览器'的默认行为 （作用范围： 浏览器行为）
 * 2）stopPropagation()：阻止 'DOM 树'的事件冒泡 （作用范围： DOM 事件流）
 * 3）stopImmediatePropagation()：阻止'同一元素的其他监听器'执行 （作用范围： 事件监听器）
 * 2、监听器执行顺序：捕获阶段 > 目标阶段（按注册顺序） > 冒泡阶段
 */
export enum PreventionStrategy {
  Default = 'default', // 先 preventDefault，后 stopPropagation
  BubbleFirst = 'bubbleFirst', // 先 stopPropagation，后 preventDefault
  PreventOnly = 'preventOnly', // 只 preventDefault
  BubbleOnly = 'bubbleOnly', // 只 stopPropagation
  Smart = 'smart', // 智能判断
  Safe = 'safe', // 安全模式
}

export enum PreventionScenario {
  Link = 'link', // 链接点击
  Form = 'form', // 表单提交
  Custom = 'custom', // 自定义组件
  Dropdown = 'dropdown', // 下拉菜单
  Contextmenu = 'contextmenu', // 右键菜单
}

/**
 * 事件阻止类型
 */
export type EventPreventionType = Event | JQuery.Event

export class EventUtils {
  get name(): string {
    return 'EventUtils'
  }

  /**
   * 按场景阻止事件
   */
  static preventEventByScenario(
    e: EventPreventionType,
    scenario: PreventionScenario,
  ): boolean {
    const strategies: Record<PreventionScenario, PreventionStrategy> = {
      [PreventionScenario.Link]: PreventionStrategy.Default,
      [PreventionScenario.Form]: PreventionStrategy.Default,
      [PreventionScenario.Custom]: PreventionStrategy.BubbleFirst,
      [PreventionScenario.Dropdown]: PreventionStrategy.BubbleOnly,
      [PreventionScenario.Contextmenu]: PreventionStrategy.PreventOnly,
    }

    return this.preventEvent(e, strategies[scenario] || PreventionStrategy.Default)
  }

  /**
   * 阻止事件默认行为和冒泡
   */
  static preventEvent(
    e: EventPreventionType,
    strategy: PreventionStrategy = PreventionStrategy.Default,
  ): boolean {
    try {
      switch (strategy) {
        case PreventionStrategy.Default:
          return this.preventEventDefault(e)

        case PreventionStrategy.BubbleFirst:
          e.stopPropagation()
          e.preventDefault()
          return true

        case PreventionStrategy.PreventOnly:
          e.preventDefault()
          return true

        case PreventionStrategy.BubbleOnly:
          e.stopPropagation()
          return true

        case PreventionStrategy.Smart:
          return this.preventEventSmart(e)

        case PreventionStrategy.Safe:
          return this.preventEventSafe(e)

        default:
          return this.preventEventDefault(e)
      }
    }
    catch (error) {
      logger.warn(`[${this.name}] 事件阻止失败:`, error)
      return this.preventEventFallback(e)
    }
  }

  /**
   * 默认阻止策略（先 preventDefault，后 stopPropagation）
   */
  static preventEventDefault(e: EventPreventionType): boolean {
    e.preventDefault()
    e.stopPropagation()
    return true
  }

  /**
   * 智能阻止策略（根据元素类型自动选择）
   */
  static preventEventSmart(e: EventPreventionType): boolean {
    const target = (e as Event).target as Element
    const tagName = target?.tagName || ''

    // 链接和表单元素优先阻止默认行为
    if (tagName === 'A' || tagName === 'FORM'
      || ['INPUT', 'SELECT', 'TEXTAREA', 'BUTTON'].includes(tagName)) {
      return this.preventEvent(e, PreventionStrategy.Default)
    }

    // 其他元素优先阻止冒泡
    return this.preventEvent(e, PreventionStrategy.BubbleFirst)
  }

  /**
   * 安全阻止策略（带错误处理）
   */
  static preventEventSafe(e: EventPreventionType): boolean {
    let success = true

    try {
      e.preventDefault()
    }
    catch (error) {
      logger.warn(`[${this.name}] preventDefault 失败:`, error)
      success = false
    }

    try {
      e.stopPropagation()
    }
    catch (error) {
      logger.warn(`[${this.name}] stopPropagation 失败:`, error)
      success = false
    }

    return success
  }

  /**
   * 回退阻止方案
   */
  static preventEventFallback(e: EventPreventionType): boolean {
    try {
      if (e.cancelable !== false) {
        e.preventDefault()
      }
      e.stopPropagation()
      return true
    }
    catch (error) {
      logger.error(`[${this.name}] 事件阻止完全失败:`, error)
      return false
    }
  }

  /**
   * 阻止其他事件处理程序
   */
  static stopImmediatePropagation(e: EventPreventionType): void {
    e.stopImmediatePropagation()
  }
}
